package com.fingard.dsp.tcpserver;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.crypto.SignEncryptHelper;
import com.fingard.diagnostics.LogHelper;
import com.fingard.dsp.Transmit;
import com.fingard.dsp.bank.DealDirectBank;
import com.fingard.dsp.bank.dbobj.secretkey.SecretKeyDataHelper;
import com.fingard.dsp.bank.helpers.FileType;
import com.fingard.dsp.bank.reqrespobj.PacketType;
import com.fingard.dsp.bank.reqrespobj.ReqRespHeader;
import com.fingard.dsp.bank.sepro.ReceiptSaveToAndTransmit;
import com.fingard.dsp.bankset.BankFront;
import com.fingard.dsp.core.DSPSecurityData;
import com.fingard.dsp.core.dao.bankpay.BankPayInfoMapper;
import com.fingard.dsp.core.dao.directchannel.DirectChannelMapper;
import com.fingard.dsp.core.dao.record.DirectCmdRecordMapper;
import com.fingard.dsp.core.entity.bankpay.BankPayInfoPO;
import com.fingard.dsp.entity.enums.ENDSPResult;
import com.fingard.dsp.entity.po.DirectChannelPO;
import com.fingard.dsp.entity.po.DirectCmdRecordPO;
import com.fingard.generalobj.ExecResponse;
import com.fingard.io.FileHelper;
import com.fingard.luna.framework.boot.core.util.SpringContextHolder;
import com.fingard.net.IpHelper;
import com.fingard.text.StringHelper;
import com.fingard.text.XmlHelper;
import com.fingard.util.HttpClientUtil;
import org.apache.commons.codec.binary.Base64;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.PublicKey;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**通过ServerSocketByThread.acceptByNewIO()启动了当前ThreadNIO的实例，
 * 本实例开启CachedThreadPool线程池来执行各个请求。
 *
 * mapBankQueue存放各个渠道队列，通过传BankQueue.bankHeader取得分配的前置机（调用bankFront.allocate），
 * 如果前置有可用线程，从当前渠道队列取得请求（RequestNIO req = bq.getReq();），
 * 通过线程执行*/
public class ThreadNIO implements Runnable{

	private ExecutorService esThreadPool;

	private volatile HashMap<String,BankQueue> mapBankQueue;

	private BankResetEvent autoResetEvent;
	private ThreadNIO(){
		mapBankQueue = new HashMap<String,BankQueue>();
		keyList = new ArrayList<String>();
//		autoResetEvent = p_resetEvent;//new BankResetEvent();

		esThreadPool = Executors.newCachedThreadPool();
	}
	public void setAutoResetEvent(BankResetEvent autoResetEvent){
		this.autoResetEvent = autoResetEvent;
	}

	public BankResetEvent getAutoResetEvent(){
		return this.autoResetEvent;
	}

	private static class singleThreadNIOHolder{
		private static final ThreadNIO INSTANCE = new ThreadNIO();
	}
	public static final ThreadNIO getInstance(){
		return singleThreadNIOHolder.INSTANCE;
	}

	private volatile ArrayList<String> keyList;

	public boolean addReq(RequestNIO p_req) throws Exception{

		//System.out.println("addReq seqIDInner:"+p_req.seqIDInner+" transSeqID:"+p_req.transSeqID);
		try {
			p_req.GetReqRespHeader();
			DSPSecurityData instance = DSPSecurityData.getInstance();
			if (!instance.isReadFileFlag()) {
				boolean result = saveReceivedATSInfoToDB(p_req, p_req.bankHeader);
				if (!result) {
					LogHelper.writeBankLog(p_req.seqIDInner, p_req.connTime, new Date(), "", p_req.bankHeader, p_req.sbLog, false);
					return false;
				}
			}
		}catch (Exception ex){
			respExpMsg(p_req, ex);
			return false;
		}
		ReqRespHeader addHeader = p_req.bankHeader.clone();
		String tmpCorporation = addHeader.corporation;
        if (tmpCorporation == null || tmpCorporation.length() == 0) {
            tmpCorporation = "5000001";
        }

        String tmpGroup = addHeader.group;
        if (tmpGroup == null || tmpGroup.length() == 0) {
            tmpGroup = "Default";
        }

        String tmpKeyDirectBank = addHeader.bankCode;
        if (addHeader.bankCode != null && addHeader.bankCode.startsWith("FnGrd") && addHeader.bankCode.length() == 8) {
            tmpKeyDirectBank = "FnGrd01";
        }
        if (addHeader.bankCode != null && addHeader.bankCode.startsWith("CSRS")) {
            tmpKeyDirectBank = "CSRSYBT11";
            addHeader.bankCode = "CSRSYBT11";
        }

        String tmpMapKey = tmpKeyDirectBank + "-" + tmpCorporation + "-" + tmpGroup + "-" + addHeader.pckType + "-" + addHeader.tenant;

        if(!mapBankQueue.containsKey(tmpMapKey)){
        	synchronized(mapBankQueue){
        		if(!mapBankQueue.containsKey(tmpMapKey)){
        			mapBankQueue.put(tmpMapKey, new BankQueue(addHeader));
                	keyList.add(tmpMapKey);
        		}
        	}
        }
//		System.out.println("添加队列完成"+new Date());
       boolean result = mapBankQueue.get(tmpMapKey).addReq(p_req);
       if(result){
		   this.autoResetEvent.set();
	   }
		return result;

	}


	/**
	 * 接收ATS信息入库
	 *
	 * @param p_bizO
	 * @param tmpHeader
	 */
	private boolean saveReceivedATSInfoToDB(RequestNIO p_bizO, ReqRespHeader tmpHeader) throws IOException, ParseException {
		String tmpRespBody = "";
		DirectCmdRecordMapper recordMapper = SpringContextHolder.getBean(DirectCmdRecordMapper.class);
		DirectChannelMapper directChannelMapper = SpringContextHolder.getBean(DirectChannelMapper.class);
		DirectCmdRecordPO recordPO = new DirectCmdRecordPO();
		Map<String, Object> recordParam = new HashMap<>();
		recordParam.put("transseqid", p_bizO.bankHeader.transSeqID);
		//检测请求流水号是否重复
		List<DirectCmdRecordPO> cmdRecordPOS = recordMapper.selectByMap(recordParam);
		if (cmdRecordPOS.size() > 0) {
			tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>" + ENDSPResult.COMMAND_RESUBMIT.code() + "</RespCode><RespInfo>" + ENDSPResult.COMMAND_RESUBMIT.msg() + "，请检测是否重复提交指令！</RespInfo></TransParam></TransResp></ATSYH>";
			p_bizO.writeRespBody(false, "", tmpRespBody);
			p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(new Date()) + " 4.返回ATS的报文：\r\n" + tmpRespBody);
			return false;
		}
		//查询提交前检查支付提交是否已发起
		if (PacketType.PayQuery.equals(p_bizO.bankHeader.pckType)) {
			BankPayInfoMapper bankPayInfoMapper = SpringContextHolder.getBean(BankPayInfoMapper.class);
			QueryWrapper<BankPayInfoPO> wrapper = new QueryWrapper<>();
			wrapper
					.eq("REQSEQID", p_bizO.bankHeader.reqSeqID);
			List<BankPayInfoPO> bankPayInfoPOS = bankPayInfoMapper.selectList(wrapper);
			if (bankPayInfoPOS.size() == 0) {
				tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>" + ENDSPResult.QUERY_BEFORE_PAY.code() + "</RespCode><RespInfo>" + ENDSPResult.QUERY_BEFORE_PAY.msg() + "，请检测是否重复提交指令！</RespInfo></TransParam></TransResp></ATSYH>";
				p_bizO.writeRespBody(false, "", tmpRespBody);
				p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(new Date()) + " 4.返回ATS的报文：\r\n" + tmpRespBody);
				return false;
			}
		}
		recordPO.setUrid(UUID.randomUUID().toString());
		recordPO.setDirectchannelcmd(p_bizO.bankHeader.transType);
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("CODE", p_bizO.bankHeader.bankCode);
		List<DirectChannelPO> directChannelPOS = directChannelMapper.selectByMap(paramMap);
		if (directChannelPOS == null || directChannelPOS.size() != 1) {
			tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>" + ENDSPResult.DIRECTCHANNEL_NOT_EXIST.code() + "</RespCode><RespInfo>" + ENDSPResult.DIRECTCHANNEL_NOT_EXIST.msg() + "，请确认渠道信息是否正确！</RespInfo></TransParam></TransResp></ATSYH>";
			p_bizO.writeRespBody(false, "", tmpRespBody);
			p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(new Date()) + " 4.返回ATS的报文：\r\n" + tmpRespBody);
			return false;
		}
		recordPO.setDirectchannelid(directChannelPOS.get(0).getUrid());
		recordPO.setDspip(FGBiz.localHostIp);
		recordPO.setTransseqid(p_bizO.bankHeader.transSeqID);
		recordPO.setCreatedby("");
		recordPO.setLastmodifiedby("");
		Date date = new Date();
		recordPO.setCreatedon(date);
		Date requestDate = Format.DateTimeFormat.parse(tmpHeader.transTime);
		recordPO.setRequesttime(requestDate);
		recordPO.setLastmodifiedon(date);
		if (PacketType.Pay.equals(p_bizO.bankHeader.pckType)) {
			recordPO.setCommandcode(p_bizO.bankHeader.commandCode);
		}
		if (StringHelper.isNullOrEmpty(p_bizO.bankHeader.tenant)) {
			recordPO.setTenantid(null);
		} else {
			recordPO.setTenantid(p_bizO.bankHeader.tenant);
		}
		recordPO.setRowversion(1);
		recordMapper.insert(recordPO);
		return true;
	}


	/**
	 * 返回错误信息
	 */
	public static void respExpMsg(RequestNIO p_req,Exception ex) throws Exception{
		try{
			byte[] tmpBytesBody = ex.getMessage().getBytes(p_req.reqSocketReceiver.charsetName);
			String tmpStrLen = String.format("% 8d", tmpBytesBody.length);

			StringBuilder tmpRespHead = new StringBuilder();
			if((p_req.reqSocketReceiver.isHttp || p_req.request != null) && FGBiz.dspCenter.dspSet.enableHttp){
				tmpRespHead.append("HTTP/1.1 200 OK\r\n");
				tmpRespHead.append("Server: DSP Web Server\r\nDate: "+Format.toGMT(new Date())+"\r\n");
				if((p_req.reqSocketReceiver.isHttp || p_req.request != null) && "/dsp/hb".equalsIgnoreCase(p_req.reqSocketReceiver.visitPage)){
					tmpRespHead.append("Content-Type: text; charset="+FGBiz.dspCenter.dspSet.encodingWithDspClient+"\r\n");
				}else if((p_req.reqSocketReceiver.isHttp || p_req.request != null) && "/dsp/encrypt".equalsIgnoreCase(p_req.reqSocketReceiver.visitPage)){
					tmpRespHead.append("Content-Type: text; charset="+FGBiz.dspCenter.dspSet.encodingWithDspClient+"\r\n");
				}else{
					tmpRespHead.append("Content-Type: text/xml; charset="+FGBiz.dspCenter.dspSet.encodingWithDspClient+"\r\n");
				}
				tmpRespHead.append("Content-Length: " + tmpStrLen + "\r\nConnection: close\r\n\r\n");
			}else{
				tmpRespHead.append("Content-Length:" + tmpStrLen + "\r\n");
			}
			byte[] tmpBytesHead = tmpRespHead.toString().getBytes(p_req.reqSocketReceiver.charsetName);

			byte[] tmpBytesResp = new byte[tmpBytesHead.length + tmpBytesBody.length];
			System.arraycopy(tmpBytesHead, 0, tmpBytesResp, 0, tmpBytesHead.length);
			System.arraycopy(tmpBytesBody, 0, tmpBytesResp, tmpBytesHead.length, tmpBytesBody.length);
			if(p_req.isRemotingInvoke){
				p_req.writeBytesForRemoting(tmpBytesResp);
			}else if(p_req.isInvokeByHttp){
				DataOutputStream tmpRespOutput = new DataOutputStream(p_req.reqSocketReceiver.socketClient.getOutputStream());
				tmpRespOutput.write(tmpBytesResp);
				tmpRespOutput.close();
				p_req.reqSocketReceiver.socketClient.close();
			}else if(p_req.request != null && StringHelper.hasAnyChar(p_req.xmlData)){
//			response.getOutputStream().write(tmpBytesResp);
				p_req.respData = new String(tmpBytesResp,p_req.reqSocketReceiver.charsetName);
				try {
					p_req.barrier.await();//阻塞
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (BrokenBarrierException e) {
					e.printStackTrace();
				}
			}else {
				ByteBuffer bs = ByteBuffer.wrap(tmpBytesResp);
				p_req.reqSocketReceiver.clientSocketChannel.configureBlocking(true);
				p_req.reqSocketReceiver.clientSocketChannel.write(bs);
			}
		}catch(Exception exIn){
			FGBiz.limitMsg.exception("ThreadNIO.run", exIn);
		}finally{
			if(p_req.reqSocketReceiver.clientSocketChannel!=null){
				p_req.reqSocketReceiver.clientSocketChannel.close();
			}
		}
	}

	private boolean needStop;
	public String stop(){
		needStop = true;
		esThreadPool.shutdown();
		return "";
	}
	
	private volatile Date lastWaitOneTime = new Date();
	
	/**获取运行时摘要信息*/
	public Map<String, String> getSummary(){
		Map<String,String> retMap = new LinkedHashMap<String,String>();
		
		retMap.put("lastWaitOneTime", Format.DateTimeFormat.format(lastWaitOneTime));
		
        return retMap;
	}
	
	

	public void run() {
		needStop = false;
		long countHttpDistribute = 0;
		for(;;){
			try{
				if(needStop){
					break;
				}
				//System.out.println("--");
				int countExecReq = 0;
				for(int i=0;i<keyList.size();i++){
					BankQueue bq = mapBankQueue.get(keyList.get(i));
					//System.out.println(keyList.get(i));
					while(bq.countReq()>0){
						//System.out.println("bq.countReq() "+bq.countReq());
//						System.out.println("开始处理"+new Date());
						RequestNIO req = null;
						BankFront bankFront = null;
						boolean isExec = false;
						StringBuilder sbLog = new StringBuilder();
                        boolean isTrustedSourceIP = true;
                        String remoteAddress = "";
						try{

							Transmit tmpTransmit = new Transmit(null, FGBiz.dspCenter.rootDirPath);
							String transType = "";
							if(StringHelper.hasAnyChar(bq.bankHeader.transType)){
								transType = bq.bankHeader.transType.toLowerCase();
							}
	                        if (tmpTransmit.isTransmit(bq.bankHeader) || "getbankfrontstatus".equals(transType) || "getstartlog".equals(transType) || "getdsplog".equals(transType)) {
	                        	isExec = true;
	                        }else if(FGBiz.tenantServer.isRemoting(bq.bankHeader.tenant)){
								isExec = true;
                        	}else{
                                bankFront = DealDirectBank.getBankFrontByHead(bq.bankHeader);
								if(bankFront == null) {
									req = bq.getReq();
									//TODO 租户级IP白名单校验
									// region 限制ip白名单
									//获取客户端IP地址
									if (req.request != null) {
										remoteAddress = req.request.getRemoteAddr();
									} else if (req.reqSocketReceiver.isHttp) {
										Map<String, String> map = req.reqSocketReceiver.headKV;
										remoteAddress = HttpClientUtil.getIpAddr(map);
										if (StringHelper.isNullOrEmpty(remoteAddress)) {
											remoteAddress = req.reqSocketReceiver.clientSocketChannel.socket().getInetAddress().getHostAddress();
										}
									} else {
										remoteAddress = req.reqSocketReceiver.clientSocketChannel.socket().getInetAddress().getHostAddress();
									}
									if (!DSPSecurityData.getInstance().getIpWhiteList().get(req.bankHeader.tenant).contains(remoteAddress)) {
										isTrustedSourceIP = false;
									}
									//endregion

									if (req.reqSocketReceiver.isHttp) {
										if (tmpTransmit.isHttpDistribute(req.reqSocketReceiver.visitPage)) {
											countHttpDistribute++;
											if (countHttpDistribute == 1) {
												FGBiz.limitMsg.addConsole("HttpDistribute", "分发http请求页面" + req.reqSocketReceiver.visitPage + "至" + tmpTransmit.serverIP + ":" + tmpTransmit.serverPort);
											}
											req.isHttpDistribute = true;
											req.transmit = tmpTransmit;
											tmpTransmit._bizO = req;
											tmpTransmit.hostRawString = req.reqSocketReceiver.hostRawString;
											isExec = true;
										}
									}
									if (!isExec) {
										try {
											String tmpRespBody = "无信息";
											if (isTrustedSourceIP == false) {
												FGBiz.limitMsg.warning("acceptByNewIO", "IP地址：" + remoteAddress + " IS REFUSED");
												tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>未检测到对应租户的IP白名单</RespInfo></TransParam></TransResp></ATSYH>";
											} else if (req.reqSocketReceiver.isSyncFile) {
												boolean isTransToMain = false;
												if (FileType.receipt.equalsIgnoreCase(req.reqSocketReceiver.fileType)) {
													ReceiptSaveToAndTransmit rcptTransmit = new ReceiptSaveToAndTransmit();
													ExecResponse resp = rcptTransmit.transmitSyncFile(req);
													if (rcptTransmit.isTransmit) {//是转发
														isTransToMain = rcptTransmit.isTransmit;
														tmpRespBody = resp.getResultAsString();
														if (!resp.isSucceed) {
															sbLog.append(resp.logMsg);
														}
													}
												}
												if (isTransToMain == false) {
													tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>" + req.reqSocketReceiver.syncCode + "</RespCode><RespInfo>" + XmlHelper.encode(req.reqSocketReceiver.syncMsg) + "</RespInfo></TransParam></TransResp></ATSYH>";
												}
											} else if ("savetodb".equalsIgnoreCase(req.reqSocketReceiver.action)) {
												ReceiptSaveToAndTransmit rcptSaveTo = new ReceiptSaveToAndTransmit();
												ExecResponse resp = rcptSaveTo.saveToOrTransmitDb(req);
												if (!resp.isSucceed) {
													sbLog.append(resp.logMsg);
												}
												tmpRespBody = resp.getResultAsString();
												if (StringHelper.isNullOrEmpty(tmpRespBody)) {
													tmpRespBody = resp.logMsg;
												}
											} else if (req.reqSocketReceiver.isHttp && "/dsp/hb".equalsIgnoreCase(req.reqSocketReceiver.visitPage)) {
												tmpRespBody = "000000";
											} else if (req.reqSocketReceiver.isHttp && "/dsp/encrypt".equalsIgnoreCase(req.reqSocketReceiver.visitPage)) {
												// 接收的数据格式   tenant_yyyyMMdd(base)
												try {
													if (!FGBiz.dspCenter.dspSet.enableEncrypt) {
														throw new Exception("当前服务没有启用通讯加密功能!");
													}
													String objStr = StringHelper.getTagContext(req.clientReqStr, "KeyObj");
													sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + "\t接收的报文为：" + req.clientReqStr + "\r\n");
													byte[] plainData = SignEncryptHelper.doDecryptByRSA(Base64.decodeBase64(objStr), FGBiz.dspCenter.dspSet.certConfig.ownPriKey);
													if (plainData == null) {
														throw new Exception("请检查请求方的公钥配置是否正确");
													}
													String plain = new String(plainData, req.reqSocketReceiver.charsetName);
													sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + "\t解密之后的原文：" + plain + "\r\n");
													String[] objs = plain.split("_");
													if (objs.length != 2) {
														tmpRespBody = "000002" + "参数格式有误";
													} else {
														PublicKey publicKey = FGBiz.dspCenter.dspSet.certConfig.custCerMap.get(objs[0]);
														if (publicKey == null) {
															throw new Exception("certificate.xml文件没有配置客户" + objs[0] + "的公钥!");
														}

														Date objDate = Format.Date8Format.parse(objs[1]);
														SecretKeyDataHelper secretKeyDataHelper = new SecretKeyDataHelper(objs[0], objDate);
														String key = secretKeyDataHelper.createEffectiveKey(objDate);
														String base64Str = SignEncryptHelper.doEncryptByRSA2(key.getBytes(req.reqSocketReceiver.charsetName), publicKey);
														tmpRespBody = "000000" + base64Str;
													}
												} catch (Exception ex) {
													FGBiz.limitMsg.exception("ThreadNIO.run", ex);
													tmpRespBody = "000001" + ex.getMessage();
												}
												sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + "\t返回客户端的报文为：" + tmpRespBody + "\r\n");
//										没有则生产入库
											} else if ("getfile".equalsIgnoreCase(req.reqSocketReceiver.action)) {
												String logFilePath = req.reqSocketReceiver.oriFilePath;
												String logFileDir = FGBiz.dspCenter.dspSet.bankLogsDirPath + File.separator + FGBiz.dspCenter.dspSet.bankLogsFirstDir + File.separator + logFilePath.split("_")[0];
												if (FileHelper.existFile(logFileDir)) {
													File[] logFiles = new File(logFileDir).listFiles();
													for (File logFile : logFiles) {
														if (logFilePath.split("_")[1].equalsIgnoreCase(logFile.getName().substring(logFile.getName().lastIndexOf("_") + 1).replace(".txt", ""))) {
															tmpRespBody = FileHelper.readFileText(logFile.getAbsolutePath(), FGBiz.dspCenter.dspSet.charsetName);
														}
													}
												} else {
													tmpRespBody = "本机DSP（" + IpHelper.getLocalHostIp() + ":" + FGBiz.dspCenter.dspSet.listenerPort + "）日志文件目录:[" + logFileDir + "]不存在,暂无法查看日志!";
												}
											} else {
												sbLog.append(Format.DateTimeSSSFormat.format(new Date()) + " 找不到前置机，key：" + bq.bankHeader.bankCode + "-" + bq.bankHeader.corporation + "-" + bq.bankHeader.group + "-" + bq.bankHeader.tenant + "\r\n");
												tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>无前置机：" + sbLog.toString() + "</RespInfo></TransParam></TransResp></ATSYH>";
											}
											byte[] tmpBytesBody = tmpRespBody.getBytes(req.reqSocketReceiver.charsetName);
											String tmpStrLen = String.format("% 8d", tmpBytesBody.length);

											StringBuilder tmpRespHead = new StringBuilder();
											if ((req.reqSocketReceiver.isHttp || req.request != null) && FGBiz.dspCenter.dspSet.enableHttp) {
												tmpRespHead.append("HTTP/1.1 200 OK\r\n");
												tmpRespHead.append("Server: DSP Web Server\r\nDate: " + Format.toGMT(new Date()) + "\r\n");
												if ((req.reqSocketReceiver.isHttp || req.request != null) && "/dsp/hb".equalsIgnoreCase(req.reqSocketReceiver.visitPage)) {
													tmpRespHead.append("Content-Type: text; charset=" + FGBiz.dspCenter.dspSet.encodingWithDspClient + "\r\n");
												} else if ((req.reqSocketReceiver.isHttp || req.request != null) && "/dsp/encrypt".equalsIgnoreCase(req.reqSocketReceiver.visitPage)) {
													tmpRespHead.append("Content-Type: text; charset=" + FGBiz.dspCenter.dspSet.encodingWithDspClient + "\r\n");
												} else {
													tmpRespHead.append("Content-Type: text/xml; charset=" + FGBiz.dspCenter.dspSet.encodingWithDspClient + "\r\n");
												}
												tmpRespHead.append("Content-Length: " + tmpStrLen + "\r\nConnection: close\r\n\r\n");
											} else {
												tmpRespHead.append("Content-Length:" + tmpStrLen + "\r\n");
											}
											byte[] tmpBytesHead = tmpRespHead.toString().getBytes(req.reqSocketReceiver.charsetName);

											byte[] tmpBytesResp = new byte[tmpBytesHead.length + tmpBytesBody.length];
											System.arraycopy(tmpBytesHead, 0, tmpBytesResp, 0, tmpBytesHead.length);
											System.arraycopy(tmpBytesBody, 0, tmpBytesResp, tmpBytesHead.length, tmpBytesBody.length);
											if (req.isRemotingInvoke) {
												req.writeBytesForRemoting(tmpBytesResp);
											} else if (req.request != null && StringHelper.hasAnyChar(req.xmlData)) {
												req.respData = new String(tmpBytesResp, req.reqSocketReceiver.charsetName);
												try {
													req.barrier.await();//阻塞
												} catch (InterruptedException e) {
													e.printStackTrace();
												} catch (BrokenBarrierException e) {
													e.printStackTrace();
												}
											} else if (req.isInvokeByHttp) {
												DataOutputStream tmpRespOutput = new DataOutputStream(req.reqSocketReceiver.socketClient.getOutputStream());
												tmpRespOutput.write(tmpBytesResp);
												tmpRespOutput.close();
												req.reqSocketReceiver.socketClient.close();
											} else {
												ByteBuffer bs = ByteBuffer.wrap(tmpBytesResp);
												req.reqSocketReceiver.clientSocketChannel.configureBlocking(true);
												req.reqSocketReceiver.clientSocketChannel.write(bs);
											}

										} catch (Exception ex) {
											FGBiz.limitMsg.exception("ThreadNIO.run", ex);
											sbLog.append(LogHelper.getStackTrace(ex));
										} finally {
											if (req.reqSocketReceiver.clientSocketChannel != null) {
												req.reqSocketReceiver.clientSocketChannel.close();
											}
										}
										if (!req.reqSocketReceiver.isHttp || !"/dsp/encrypt".equalsIgnoreCase(req.reqSocketReceiver.visitPage)) {
											sbLog.append(Format.DateTimeSSSFormat.format(new Date()) + "\t接收的报文为：" + req.clientReqStr + "\r\n");
										}
										//LogHelper.writeBankLogByHour(new Date(), "", bq.bankHeader, sbLog);
										FGBiz.logTrace.infoNoTimeBank(bq.bankHeader.bankCode, bq.bankHeader.transType, sbLog.toString());
										continue;
									}
								}else if(bankFront.allocate(bq.bankHeader)){
									isExec = true;
								}else{
									bq.isBlocked = true;
									break;
								}
	                        }
						}catch(Exception ex){//异常继续
							isExec = true;
							FGBiz.limitMsg.exception("ThreadNIO.run", ex);
							sbLog.append(LogHelper.getStackTrace(ex)+"\r\n");
							LogHelper.writeBankLogByHour(new Date(), "", bq.bankHeader, sbLog);
						}
                        if(isExec){
                        	bq.isBlocked = false;
							countExecReq++;
							if(req == null){
								req = bq.getReq();
							}
							int httpDistributeType = 0;
							if(req.isHttpDistribute){
								req.transmit.initHttpDistribute();
								httpDistributeType = 1;
							}
							req.sbLog.append(sbLog);
							ThreadEachReqNIO threadReq = new ThreadEachReqNIO(req, bankFront,autoResetEvent, FGBiz.dspCenter.getPayQryController(), httpDistributeType);
							//new Thread(threadReq).start();
							esThreadPool.execute(threadReq);
							if(req.isHttpDistribute){
								httpDistributeType = 2;
								ThreadEachReqNIO threadReq2 = new ThreadEachReqNIO(req, bankFront,autoResetEvent, FGBiz.dspCenter.getPayQryController(), httpDistributeType);
								esThreadPool.execute(threadReq2);
							}
                        }
					}
					//System.out.println("bq.countReq() "+bq.countReq());
					if(bq.countReq() == 0){
						bq.isBlocked = true;
					}
				}
				if(countExecReq == 0){
					boolean needWait = true;
					for(int i=0;i<keyList.size();i++){
						BankQueue bq = mapBankQueue.get(keyList.get(i));
						if(bq.isBlocked == false){
							needWait = false;
						}
					}
					if(needWait){
						lastWaitOneTime = new Date();
						this.autoResetEvent.waitOne();
					}
				}
			} catch(Throwable e){
				FGBiz.limitMsg.exception("ThreadNIO.run", e);
			}
		}
	}
}
